package com.hanser.hancoder.utils;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.hanser.hancoder.exception.BusinessException;
import com.hanser.hancoder.exception.ErrorCode;
import io.github.bonigarcia.wdm.WebDriverManager;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.time.Duration;
import java.util.UUID;

/*
截图工具类
 */
@Slf4j
public class WebScreenshotUtils {

    private static final int DEFAULT_WIDTH = 1600;

    private static final int DEFAULT_HEIGHT = 900;

    private static final ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>();

    /**
     * 获取WebDriver实例（线程安全）
     */
    public static WebDriver getWebDriver() {
        WebDriver driver = driverThreadLocal.get();
        if (driver == null || !isDriverAlive(driver)) {
            // 如果driver为null或者已失效，创建新的实例
            if (driver != null) {
                try {
                    driver.quit();
                } catch (Exception e) {
                    log.warn("清理失效driver时出错", e);
                }
            }
            driver = initChromeDriver(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            driverThreadLocal.set(driver);
        }
        return driver;
    }

    /**
     * 检查WebDriver实例是否仍然有效
     */
    private static boolean isDriverAlive(WebDriver driver) {
        try {
            // 尝试获取当前URL来检查会话是否有效
            driver.getCurrentUrl();
            return true;
        } catch (Exception e) {
            log.debug("WebDriver实例已失效: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 验证URL格式是否有效
     */
    private static boolean isValidUrl(String url) {
        try {
            // 基本URL格式检查
            if (!url.startsWith("http://") && !url.startsWith("https://")) {
                return false;
            }
            // 使用Java内置的URL类进行更严格的验证
            new java.net.URL(url);
            return true;
        } catch (Exception e) {
            log.debug("URL格式无效: {}", url);
            return false;
        }
    }

    /**
     * 清理当前线程的WebDriver实例
     */
    public static void cleanupWebDriver() {
        WebDriver driver = driverThreadLocal.get();
        if (driver != null) {
            try {
                driver.quit();
                log.info("Chrome浏览器实例已关闭");
            } catch (Exception e) {
                log.error("关闭Chrome浏览器时出错", e);
            } finally {
                driverThreadLocal.remove();
            }
        }
    }

    /**
     * 保存网页截图（使用完毕后会自动清理浏览器实例）
     *
     * @param url 网页路径
     * @return 截图保存路径
     */
    public static String saveWebPageScreenshot(String url) {
        WebDriver driver = null;
        try {
            // 非空校验
            if (StrUtil.isBlank(url)) {
                log.error("网页截取失败，网页路径为空！");
                return null;
            }
            
            // URL格式验证
            if (!isValidUrl(url)) {
                log.error("网页截取失败，URL格式无效：{}", url);
                return null;
            }
            // 创建临时目录
            String rootPath = System.getProperty("user.dir") + "/tmp/screenshots/" + UUID.randomUUID().toString().substring(0, 8);
            FileUtil.mkdir(rootPath);
            // 图片后缀
            final String IMAGE_SUFFIX = ".png";
            // 原始图片路径
            String imageSavePath = rootPath + File.separator + RandomUtil.randomNumbers(5) + IMAGE_SUFFIX;
            
            // 获取WebDriver实例并保存引用
            driver = getWebDriver();
            
            // 访问网页
            driver.get(url);
            // 等待页面加载完成
            waitForPageLoad(driver);
            
            // 再次验证driver是否有效（防止在等待过程中失效）
            if (!isDriverAlive(driver)) {
                log.warn("WebDriver在页面加载过程中失效，重新创建实例");
                driver = getWebDriver();
            }
            
            // 截图
            byte[] screenshotBytes = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
            // 保存原始图片
            saveImage(screenshotBytes, imageSavePath);
            log.info("原始图片保存成功：{}", imageSavePath);
            // 压缩图片
            final String COMPRESSED_IMAGE_SUFFIX = "_compressed.jpg";
            String compressedImageSavePath = rootPath + File.separator + RandomUtil.randomNumbers(5) + COMPRESSED_IMAGE_SUFFIX;
            compressImage(imageSavePath, compressedImageSavePath);
            log.info("压缩图片成功：{}", compressedImageSavePath);
            // 删除原始图片
            FileUtil.del(imageSavePath);
            return compressedImageSavePath;
        } catch (Exception e) {
            log.error("网页截图失败：{}", url, e);
            // 如果是会话相关异常，清理当前driver
            if (e.getMessage() != null && (e.getMessage().contains("session") || e.getMessage().contains("Session"))) {
                log.warn("检测到会话异常，清理当前WebDriver实例");
                cleanupWebDriver();
            }
            return null;
        } finally {
            // 关键修复：每次截图完成后立即清理浏览器实例
            cleanupWebDriver();
        }
    }

    /**
     * 初始化 Chrome 浏览器驱动（优化资源管理）
     */
    private static WebDriver initChromeDriver(int width, int height) {
        try {
            // 自动管理 ChromeDriver
            WebDriverManager.chromedriver().setup();
            // 配置 Chrome 选项
            ChromeOptions options = new ChromeOptions();
            // 无头模式
            options.addArguments("--headless");
            // 禁用GPU（在某些环境下避免问题）
            options.addArguments("--disable-gpu");
            // 禁用沙盒模式（Docker环境需要）
            options.addArguments("--no-sandbox");
            // 禁用开发者shm使用
            options.addArguments("--disable-dev-shm-usage");
            // 设置窗口大小
            options.addArguments(String.format("--window-size=%d,%d", width, height));
            // 禁用扩展
            options.addArguments("--disable-extensions");
            // 设置用户代理
            options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            
            // 新增优化选项 - 防止进程堆积
            options.addArguments("--disable-background-timer-throttling");
            options.addArguments("--disable-backgrounding-occluded-windows");
            options.addArguments("--disable-renderer-backgrounding");
            options.addArguments("--disable-features=TranslateUI,VizDisplayCompositor");
            options.addArguments("--disable-ipc-flooding-protection");
            options.addArguments("--disable-background-networking");
            options.addArguments("--disable-default-apps");
            options.addArguments("--disable-hang-monitor");
            options.addArguments("--disable-prompt-on-repost");
            options.addArguments("--disable-sync");
            options.addArguments("--disable-web-resources");
            options.addArguments("--metrics-recording-only");
            options.addArguments("--no-first-run");
            options.addArguments("--safebrowsing-disable-auto-update");
            options.addArguments("--disable-logging");
            options.addArguments("--disable-plugins");
            // 移除--single-process，因为它在新版Chrome中可能导致会话问题
            options.addArguments("--disable-blink-features=AutomationControlled");
            options.addArguments("--disable-web-security");
            options.addArguments("--allow-running-insecure-content");
            
            // 内存和性能优化
            options.addArguments("--memory-pressure-off");
            options.addArguments("--max_old_space_size=4096");
            
            // 稳定性优化
            options.addArguments("--disable-features=VizDisplayCompositor,VizHitTestSurfaceLayer");
            options.addArguments("--disable-crash-reporter");
            options.addArguments("--disable-in-process-stack-traces");
            
            // 创建驱动
            WebDriver driver = new ChromeDriver(options);
            // 设置页面加载超时（缩短超时时间）
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(20));
            // 设置隐式等待（缩短等待时间）
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
            
            log.info("Chrome浏览器实例已创建");
            return driver;
        } catch (Exception e) {
            log.error("初始化 Chrome 浏览器失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "初始化 Chrome 浏览器失败");
        }
    }

    /**
     * 保存图片
     *
     * @param imageBytes 图片字节数组
     * @param imagePath  图片保存路径
     */
    public static void saveImage(byte[] imageBytes, String imagePath) {
        try {
            FileUtil.writeBytes(imageBytes, imagePath);
        } catch (Exception e) {
            log.error("保存图片失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存图片失败");
        }
    }

    /**
     * 压缩图片
     *
     * @param originalImagePath   原图片路径
     * @param compressedImagePath 压缩图片路径
     */
    private static void compressImage(String originalImagePath, String compressedImagePath) {
        final float COMPRESSION_QUALITY = 0.3f;
        try {
            ImgUtil.compress(
                    FileUtil.file(originalImagePath),
                    FileUtil.file(compressedImagePath),
                    COMPRESSION_QUALITY
            );
        } catch (Exception e) {
            log.error("压缩图片失败：{}->{}", originalImagePath, compressedImagePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "压缩图片失败");
        }
    }

    private static void waitForPageLoad(WebDriver webDriver) {
        try {
            // 首先检查driver是否有效
            if (!isDriverAlive(webDriver)) {
                log.warn("WebDriver实例在页面加载等待前已失效");
                return;
            }
            
            WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(10));
            boolean complete = wait.until(driver -> {
                try {
                    return ((JavascriptExecutor) driver)
                            .executeScript("return document.readyState")
                            .equals("complete");
                } catch (Exception e) {
                    log.debug("检查页面加载状态时出错: {}", e.getMessage());
                    return false;
                }
            });
            
            // 额外等待，确保页面完全加载
            Thread.sleep(2000);
            log.info("页面加载完成！");
        } catch (Exception e) {
            log.error("等待页面加载时出错，继续执行截图操作！", e);
            // 如果是会话相关异常，不要继续等待
            if (e.getMessage() != null && (e.getMessage().contains("session") || e.getMessage().contains("Session"))) {
                throw new RuntimeException("WebDriver会话异常", e); // 包装为RuntimeException
            }
        }
    }

    /**
     * 应用关闭时清理所有浏览器实例
     * 注意：这个方法主要用于应急情况，正常情况下应该在每次使用完后调用cleanupWebDriver()
     */
    public static void destroyAllDrivers() {
        try {
            cleanupWebDriver();
            log.info("所有Chrome浏览器实例已清理");
        } catch (Exception e) {
            log.error("清理Chrome浏览器实例时出错", e);
        }
    }
}

